package com.sec.etech.common.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sec.etech.bpm.constant.DBConstant;
import com.sec.etech.bpm.cust.mapper.EtechTaskOpinionExtMapper;
import com.sec.etech.bpm.cust.model.EtechTaskOpinionExt;
import com.sec.etech.bpm.cust.service.EtechBpmService;
import com.sec.etech.bpm.cust.service.FlowSpecialCheckService;
import com.sec.etech.org.service.EtechGroupService;
import com.sec.etech.sys.cal.service.WorkCalService;
import lombok.extern.slf4j.Slf4j;
import org.openbpm.base.core.util.StringUtil;
import org.openbpm.bpm.api.engine.action.cmd.TaskActionCmd;
import org.openbpm.bpm.api.model.nodedef.BpmNodeDef;
import org.openbpm.bpm.api.service.BpmProcessDefService;
import org.openbpm.bpm.core.manager.BpmInstanceManager;
import org.openbpm.bpm.core.manager.BpmTaskManager;
import org.openbpm.bpm.core.manager.BpmTaskOpinionManager;
import org.openbpm.bpm.core.manager.TaskIdentityLinkManager;
import org.openbpm.bpm.core.model.BpmInstance;
import org.openbpm.bpm.core.model.BpmTask;
import org.openbpm.bpm.core.model.BpmTaskOpinion;
import org.openbpm.bpm.core.model.TaskIdentityLink;
import org.openbpm.bus.api.model.IBusinessData;
import org.openbpm.form.util.DateUtils;
import org.openbpm.sys.api.model.DefaultIdentity;
import org.openbpm.sys.api.model.SysIdentity;
import org.openbpm.sys.api.service.ISysDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Slf4j
@Service
public class EtechFlowCheckHelper implements FlowSpecialCheckService {
    @Resource
    EtechBpmService etechBpmService;

    @Resource
    private WorkCalService workCalService;

    @Resource
    private EtechTaskOpinionExtMapper taskOpinionExtMapper;
    @Autowired
    private ISysDataSourceService sysDataSourceService;

    @Resource
    BpmInstanceManager bpmInstanceManager;

    @Autowired
    BpmProcessDefService bpmProcessDefService;

    @Resource
    BpmTaskManager bpmTaskManager;

    @Resource
    BpmTaskOpinionManager bpmTaskOpinionManager;

    @Resource
    TaskIdentityLinkManager taskIdentityLinkManager;
    @Autowired
    CommonService commonService;
    @Autowired
    EtechGroupService etechGroupService;

    @Override
    public void onTaskCreate(TaskActionCmd taskActionModel, BpmNodeDef nodeDef, EtechTaskOpinionExt taskOpinionExt) {
        String defKey = taskOpinionExt.getDefKey();
        JSONObject bizObject = null;
        for (Map.Entry<String, IBusinessData> entry : taskActionModel.getBizDataMap().entrySet()) {
            if (entry.getValue() != null) {
                bizObject = new JSONObject(entry.getValue().getData());
                break;
            }
        }

        String nodeKey = taskOpinionExt.getTaskKey();
        String nodeName = taskOpinionExt.getTaskName();

        // 检查 计划送审时间 => 预期完成时间 （任务创建时）
        updatePlanComplateDayWithPlandate(taskOpinionExt, bizObject);
        //产品清单 分配 节点责任科室设置
        if("T19.1,T19.2,T19.3,T19.4,T19.5".indexOf(nodeKey)>-1 && "nlist_85_2".equalsIgnoreCase(defKey)){
            String key = "";
            if("T19.1".equals(nodeKey) && bizObject.getLong("s1designdprtid")!=null && bizObject.getLong("s1designdprtid")>0){
                key = "s1designdprtid";
            }
            if("T19.2".equals(nodeKey) && bizObject.getLong("s2designdprtid")!=null && bizObject.getLong("s2designdprtid")>0){
                key = "s2designdprtid";
            }
            if("T19.3".equals(nodeKey) && bizObject.getLong("s3designdprtid")!=null && bizObject.getLong("s3designdprtid")>0){
                key = "s3designdprtid";
            }
            if("T19.4".equals(nodeKey) && bizObject.getLong("s4designdprtid")!=null && bizObject.getLong("s4designdprtid")>0){
                key = "s4designdprtid";
            }
            if("T19.5".equals(nodeKey) && bizObject.getLong("s5designdprtid")!=null && bizObject.getLong("s5designdprtid")>0){
                key = "s5designdprtid";
            }
            if(!"".equals(key)) {
                taskOpinionExt.setMasterGroup(bizObject.getString(key));
                taskOpinionExt.setMasterGroupName(etechGroupService.getGroupNameById(bizObject.getString(key)));
            }
        }
        taskOpinionExtMapper.updateById(taskOpinionExt);

        // 检查自动跳过节点
        // https://etech.coding.net/p/etech-all/all/issues/2512?filter=70c84e22bd85eb5c51ad37bc370eb1b8
        // 除产品清单 T7.4外，其他均通过流程条件配置实现。
    }


    public boolean updatePlanComplateDayWithPlandate(EtechTaskOpinionExt taskOpinionExt, JSONObject bizObject) {
        String nodeKey = taskOpinionExt.getTaskKey();
        String defKey = taskOpinionExt.getDefKey();
        String defKeyStr = "X2_1,X2_2,X2_4,X3_1,X3_10,X3_11,X3_12,X3_13,X3_2,X3_3,X3_4,X3_5,X3_6,X3_7,X3_8,X3_9";//修改单模板
        //判断流程
        if(StringUtil.isEmpty(defKey) && defKeyStr.indexOf(defKey)<0){
            return false;
        }
        // 2 获取当前计划送审时间 字段名
        Date plandate = null;
        JdbcTemplate jdbcTemplate = sysDataSourceService.getJdbcTemplateByKey(DBConstant.PLAN_DB);
        if(defKeyStr.indexOf(defKey)>-1) {//修改单流程
            String sql = "select ab.signeddate,a.compileuserid from proj_amend a, proj_amend_bpe ab " +
                    "where a.amendid=ab.amendid and ab.active=1 and ab.amendid=" + bizObject.getString("amendid");

            List<Map<String, Object>> dataList = jdbcTemplate.queryForList(sql);
            if(dataList!=null && dataList.size()>0) {
                plandate = dataList.get(0).get("signeddate") != null ? (Date) dataList.get(0).get("signeddate") : workCalService.getWorkDayByDay(new Date(), 7);//如果没填就是默认七天后
            }
            plandate = plandate != null ? plandate : workCalService.getWorkDayByDay(new Date(), 7);//如果没填就是默认七天后
        }else {
            plandate = bizObject.getDate("plandate");
            if(plandate==null) {
                String sql = "select p.plandate from proj_plantask p where p.plantaskid=" + bizObject.getString("plantaskid");
                try {
                    plandate = jdbcTemplate.queryForObject(sql, Date.class);
                } catch (Exception e) {
                }
            }
        }
        String sql = "select * from proj_plan_z_node_workday where active=1 and defkey=? and nodecode=? ";
        List<Map<String,Object>> dataList = jdbcTemplate.queryForList(sql, defKey, nodeKey);
        if(dataList!=null && dataList.size()>0) {
            for (Map<String,Object> map: dataList) {
                Integer type = (Integer) map.get("type");
                Integer days = map.get("days")==null? 0: (Integer) map.get("days");
                //设置预期完成时间
                if(type!=null && type==1 && days!=null){//计划送审日期减/加N工作日
                    plandate = workCalService.getWorkDayByDay(plandate, days);
                }
                //设置预期完成时间/反推工作日天数/剩余天数
                this.setPlanComplateDayInTaskOpinion(taskOpinionExt, plandate);
            }
        }
        return true;
    }
    public void setPlanComplateDayInTaskOpinion(EtechTaskOpinionExt taskOpinionExt, Date planComplateDay){
        if(taskOpinionExt==null || planComplateDay==null) return;
        // 设置预期完成时间
        if(planComplateDay!=null){
            planComplateDay = WorkCalService.endOfDay(planComplateDay);
        }
        if(planComplateDay!=null){
            //如果预期完成时间小于今天，设置为今天
            if(Long.parseLong(DateUtils.format(new Date(),"yyyyMMdd")) > Long.parseLong(DateUtils.format(planComplateDay, "yyyyMMdd"))){
                planComplateDay = WorkCalService.endOfDay(new Date());
            }
            planComplateDay = WorkCalService.endOfDay(planComplateDay);
        }
        taskOpinionExt.setPlanCompleteDay(planComplateDay);
        // 反推工作日天数
        Date createTime = taskOpinionExt.getCreateTime();
        if(createTime==null){
            createTime = new Date();
        }
        int workDays = workCalService.getWorkDaysByTime4remainDay(createTime, planComplateDay);
        taskOpinionExt.setPlanWorkdays(workDays);
        // 反推剩余天数
        int remainDays = workCalService.getWorkDaysByTime4remainDay(new Date(), planComplateDay);
        taskOpinionExt.setRemainDays(remainDays);
        taskOpinionExt.setCalDaysTime(new Date());

        taskOpinionExtMapper.updateById(taskOpinionExt);
    }

    /**
     * 更新指定节点类型的预期完成时间
     *
     * //@param instId           可选，如为空则有所有符合条件的节点
     * //@param nodeIds/taskKeys 节点集合
     * //@param planComplateDay
     */
    /*public boolean updatePlanComplateDayInActiveTask(String instId, String bizId, String[] nodeIds, Date planComplateDay) {

        // TODO 检查 计划送审时间 => 预期完成时间 （更改执行中任务）

        // https://etech.coding.net/p/etech-all/bug-tracking/issues/2383/detail
        // TODO【产品清单】流程-各专业方向的编制节点预期结束时间=计划送审日期，并据此算出工作日的天数
        // https://etech.coding.net/p/etech-all/bug-tracking/issues/2440/detail

        if(StringUtil.isEmpty(instId) && StringUtil.isEmpty(bizId)){
            log.warn("更新当前任务预期完成时间必须指定流程ID(instId)或业务ID(bizId)中至少一个");
            return false;
        }
        if(planComplateDay==null){
            return false;
        }
        if(nodeIds==null){
            nodeIds = noteIdsUpdateByPlandate;
        }

        LambdaQueryWrapper<EtechTaskOpinionExt> queryWrapper = new LambdaQueryWrapper<EtechTaskOpinionExt>();
        if(StringUtil.isNotEmpty(instId)){
            queryWrapper = queryWrapper.eq(EtechTaskOpinionExt::getInstId, instId);
        }else {
            // 根据业务编号获取流程ID，可能有多个，etech现有场景下不涉及到同一个业务的多个计划任务流程
            JdbcTemplate jdbcTemplate = JdbcTemplateUtil.getJdbcTemplate("dataSourceDefault");
            List<String> instList = new ArrayList<>();
            jdbcTemplate.queryForList("select inst_id_ as instId from bpm_bus_link where biz_id_="+bizId);
            jdbcTemplate.query("select inst_id_ as instId from bpm_bus_link where biz_id_=" + bizId, new RowMapper() {
                @Override
                public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                    String inst1 = rs.getString("instId");
                    instList.add(inst1);
                    return null;
                }
            });
            if(!instList.isEmpty()){
                queryWrapper = queryWrapper.in(EtechTaskOpinionExt::getInstId, instList);
            }
        }
        if(nodeIds!=null){
            queryWrapper = queryWrapper.in(EtechTaskOpinionExt::getTaskKey, Arrays.asList(nodeIds));
        }
        List<EtechTaskOpinionExt> taskList = taskOpinionExtMapper.selectList(queryWrapper);
        for(EtechTaskOpinionExt taskOpinionExt: taskList){
            String defKey = taskOpinionExt.getDefKey();
            String node = taskOpinionExt.getTaskKey();
            //产品图纸、传递图、英文图纸，T0设计提交节点的预期完成时间=T1-4个工作日（不包含双休节假日）
            //外购件流程，T0.2节点的预期完成时间=T1-4个工作日（不包含双休节假日）
            if(("componentDesign2,cdt_sg,cdt_wlz,cdt_zs,cdt_sz,ywtz".indexOf(defKey)>-1 && "T0".equalsIgnoreCase(node))
                    || ("wgj".indexOf(defKey)>-1 && "T0.2".equalsIgnoreCase(node))){
                planComplateDay = workCalService.getWorkDayByDay(planComplateDay, -4);
            }
            // 设置
            setPlanComplateDayInTaskOpinion(taskOpinionExt, planComplateDay);
            // 保存
            taskOpinionExtMapper.updateById(taskOpinionExt);
        }
        return true;
    }*/

    @Override
    public void onTaskComplete(TaskActionCmd taskActionModel, EtechTaskOpinionExt taskOpinionExt) {
        String actionName = taskActionModel.getActionName();
        String nodeKey = taskOpinionExt.getTaskKey();
        String defKey = taskOpinionExt.getDefKey();//流程模板

    }

    @Override
    public void preTaskComplete(TaskActionCmd taskActionModel, EtechTaskOpinionExt taskOpinionExt) {
    }

    /**
     * 自动提交节点
     * @param taskActionModel
     */
    public void autoSubmitNode(TaskActionCmd taskActionModel){
        etechBpmService.autoSubmitNode(taskActionModel);
    }

    public void autoSubmitNodeSimple(String nodeKey, String nodeAction, String instanceid){
        etechBpmService.autoSubmitNodeSimple2(nodeKey, nodeAction, instanceid);
    }
    /**
     * 判断流程中是否存在指定节点
     * @param instId
     * @param nodeKey
     * @return
     */
    public boolean hasNodeCode(String instId, String nodeKey){
        // 前流程图是否有指定节点序号的节点 是否有A11
        if(instId==null || nodeKey==null) return false;
        BpmInstance instance = bpmInstanceManager.get(instId);
        if(instance!=null){
            List<BpmNodeDef> nodeDefs = bpmProcessDefService.getAllNodeDef(instance.getDefId());
            for(BpmNodeDef nodeDef: nodeDefs){
                if(nodeKey.equalsIgnoreCase(nodeDef.getNodeId())){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 任务处理节点增加处理人
     * @param taskId
     * @param uid
     * @return
     */
    public String addTaskNodeUser(String taskId, String uid, String userName){
        // 任务处理节点增加处理人
        if(taskId==null || uid==null) return null;
        try {
            BpmTask task = bpmTaskManager.get(taskId);
            List<TaskIdentityLink> list = taskIdentityLinkManager.getByTaskId(taskId);
            TaskIdentityLink link2 = null;
            if (list != null) {
                for (TaskIdentityLink link : list) {
                    if ("user".equals(link.getType())) {
                        if (link2 == null) {
                            link2 = link;
                        }
                        if (uid.equalsIgnoreCase(link.getIdentity())) {
                            return null;
                        }
                    }
                }
            }
            List<SysIdentity> taskIdentitys = new ArrayList<>();
            taskIdentitys.add(new DefaultIdentity(uid, userName, "user"));
            taskIdentityLinkManager.createIdentityLink(task, taskIdentitys);

            // 同步更新 bpm_task_opinion中处理人信息
            // update TaskOpinion assignInformation
            list = taskIdentityLinkManager.getByTaskId(taskId);
            taskIdentitys = new ArrayList<>();
            for(TaskIdentityLink identityLink: list){
                SysIdentity identity = new DefaultIdentity(identityLink.getIdentity(), identityLink.getIdentityName(), identityLink.getType());
                taskIdentitys.add(identity);
            }
            StringBuilder assignInfo = new StringBuilder();
            if (CollectionUtil.isNotEmpty(taskIdentitys)) {
                for (SysIdentity identity : taskIdentitys) {
                    assignInfo.append(identity.getType()).append("-").append(identity.getName()).append("-").append(identity.getId()).append(",");
                }
            }
            EtechTaskOpinionExt taskOpinionExt = taskOpinionExtMapper.selectOne(new LambdaQueryWrapper<EtechTaskOpinionExt>().eq(EtechTaskOpinionExt::getTaskId, taskId));
            if(taskOpinionExt!=null && assignInfo.length()>0){
                taskOpinionExt.setAssignInfo(assignInfo.toString());
                taskOpinionExtMapper.updateById(taskOpinionExt);
            }

            log.debug("任务处理节点增加处理人完成, taskId={}, userId={}", taskId, uid);
        }catch (Exception e){
            log.error("任务处理节点增加处理人失败, taskId={}, userId={}", taskId, uid);
        }
        return "success";
    }

    /**
     * 检查当前流程是否处于指定节点
     * @param instId
     * @param bizId
     * @param nodeKeys
     * @return
     */
    public boolean isInCurrentNodes(String instId, String bizId, String[] nodeKeys){
        if(instId==null || nodeKeys==null) return false;
        Set<String> nodeKeySet = new HashSet<>();
        nodeKeySet.addAll(Arrays.asList(nodeKeys.clone()));
        List<BpmTask> taskList = bpmTaskManager.getByInstId(instId);
        for(BpmTask task: taskList){
            if(CollectionUtil.contains(nodeKeySet, task.getNodeId())){
                return true;
            }
        }
        return false;
    }

    /**
     * 检查当前流程是否已全部通过指定节点
     * @param instId
     * @param bizId
     * @param nodeKeys
     * @return
     */
    public boolean havePassedNodes(String instId, String bizId, String[] nodeKeys){
        //
        if(instId==null || nodeKeys==null){
            return false;
        }
        Set<String> passNodes = new HashSet<>();
        List<BpmTaskOpinion> taskOpinions = bpmTaskOpinionManager.getByInstId(instId);
        for(BpmTaskOpinion opinion: taskOpinions){
            if(!"awaiting_check".equalsIgnoreCase(opinion.getStatus())){
                passNodes.add(opinion.getTaskKey());
            }
        }
        for(String nodeKey: nodeKeys){
            if(!CollectionUtil.contains(passNodes, nodeKey)){
                return false;
            }
        }
        return true;
    }

    /**
     * 检查当前流程是否已经结束
     *
     * @param instanceId
     * @return
     */
    public boolean isInstanceEnd(String instanceId) {
        if (StrUtil.isBlank(instanceId) || "0".equals(instanceId)) return false;
        List<BpmTask> taskList = bpmTaskManager.getByInstId(instanceId);
        return CollUtil.isEmpty(taskList);
    }

    /**
     * 流程节点获取责任科室
     * @param taskId
     * @param nodeCode
     * @param instanceId
     * @return
     */
    public String getDprtidByNodeid(String taskId, String nodeCode, String instanceId) {
        LambdaQueryWrapper<EtechTaskOpinionExt> queryWrapper = new LambdaQueryWrapper<EtechTaskOpinionExt>();
        if(StringUtil.isNotEmpty(taskId)) {
            queryWrapper.eq(EtechTaskOpinionExt::getTaskId, taskId);
        }else if(StringUtil.isNotEmpty(nodeCode) || StringUtil.isNotEmpty(instanceId)){
            queryWrapper.eq(EtechTaskOpinionExt::getTaskKey, nodeCode);
            queryWrapper.eq(EtechTaskOpinionExt::getInstId, instanceId);
        }
        EtechTaskOpinionExt taskOpinionExt = taskOpinionExtMapper.selectOne(queryWrapper);
        return taskOpinionExt!=null ? taskOpinionExt.getMasterGroup(): "";
    }
    //修改产品清单分配节点处理人
    public void changeHandler(Long oldDeptId, Long newDeptId, String taskId) {
        JdbcTemplate jdbcTemplate = sysDataSourceService.getJdbcTemplateByKey(com.sec.etech.bpm.constant.DBConstant.PLAN_DB);
        //String sql = "select m.uid from proj_plantask_z_designdprt_managers m,proj_plantask_z_designdprt d where d.designdprtid=m.designdprtid and m.active = 1 and d.dprtid="+oldDeptId;
        //List<String> oldUserIds = jdbcTemplate.queryForList(sql, String.class);
        BpmTask task = bpmTaskManager.get(taskId);
        if("0".equals(task.getAssigneeId())) {
            String delSql = "delete from bpm_task_identitylink where task_id_=? ";
            jdbcTemplate.update(delSql, taskId);//删掉旧处理人
        }

        //增加新处理人
        String newSql = "select t.uid, u.fullname_ uname from proj_plantask_z_designdprt_managers t,proj_plantask_z_designdprt d,org_user u " +
                "where d.designdprtid=t.designdprtid and t.uid=u.id_ and t.active = 1 and d.dprtid="+newDeptId;
        List<Map<String, Object>> newUserIds = jdbcTemplate.queryForList(newSql);
        if(newUserIds!=null){
            if(newUserIds.size()>1) {
                String assigneeNames = "";
                for (Map<String, Object> map : newUserIds) {
                    this.addTaskNodeUser(taskId, map.get("uid").toString(), map.get("uname").toString());//增加新处理人
                    assigneeNames += "[用户]"+ map.get("uname").toString() + ";";
                }
                task.setAssigneeId("0");
                task.setAssigneeNames(assigneeNames.substring(0,assigneeNames.length()-1));
            }else if(newUserIds.size()==1){
                task.setAssigneeId(newUserIds.get(0).get("uid").toString());
                task.setAssigneeNames(newUserIds.get(0).get("uname").toString());
            }
            bpmTaskManager.update(task);
        }

        //修改责任科室
        String gSql = "select name_ from org_group where id_ = " + newDeptId.longValue();
        String deptName = jdbcTemplate.queryForObject(gSql, String.class);
        EtechTaskOpinionExt taskOpinionExt = taskOpinionExtMapper.selectOne(new LambdaQueryWrapper<EtechTaskOpinionExt>().eq(EtechTaskOpinionExt::getTaskId, taskId));
        EtechTaskOpinionExt newOpinionExt = new EtechTaskOpinionExt();
        newOpinionExt.setId(taskOpinionExt.getId());
        newOpinionExt.setMasterGroup(newDeptId.toString());//科室代码
        newOpinionExt.setMasterGroupName(deptName);//科室名称
        taskOpinionExtMapper.updateById(newOpinionExt);
    }

    //获取流程表单对象
    public JSONObject getBizObject(TaskActionCmd taskActionModel){
        JSONObject bizObject = null;
        Map<String, IBusinessData> bizDataMap = taskActionModel.getBizDataMap();
        if(bizDataMap!=null && bizDataMap.size()>0){
            String key = bizDataMap.keySet().iterator().next();
            IBusinessData businessData = bizDataMap.get(key);
            if(businessData!=null){
                bizObject = new JSONObject(businessData.getData());
            }
        }
        return bizObject;
    }
}
